package de.dhbw.karlsruhe.picsim.model.cpu.impl;

import de.dhbw.karlsruhe.picsim.model.cpu.FileMutable;
import de.dhbw.karlsruhe.picsim.model.cpu.ProgramCounterMutable;
import de.dhbw.karlsruhe.picsim.model.memory.CommandRegisterAddress;
import de.dhbw.karlsruhe.picsim.model.memory.HiddenRegisters;
import de.dhbw.karlsruhe.picsim.model.memory.impl.CommandRegisterAddressImpl;
import de.dhbw.karlsruhe.picsim.model.memory.impl.RegisterValueImpl;
import de.dhbw.karlsruhe.picsim.util.Bits;
import de.dhbw.karlsruhe.picsim.util.impl.BitUtilities;
import de.dhbw.karlsruhe.picsim.util.impl.Lengths;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;

import static de.dhbw.karlsruhe.picsim.util.impl.BitUtilities.asLeastSignificantBitFirst;

/**
 * Created by IntelliJ IDEA.
 * User: goesen
 * Date: Apr 12, 2010
 * Time: 10:03:19 PM
 */
public final class ProgramCounterImpl implements ProgramCounterMutable {
    private static final Log log = LogFactory.getLog(ProgramCounterImpl.class);
    private final HiddenRegisters hiddenRegisters;
    private final FileMutable pcl;

    public ProgramCounterImpl(final HiddenRegisters hiddenRegisters, final FileMutable pcl) {
        this.hiddenRegisters = hiddenRegisters;
        this.pcl = pcl;
    }

    /**
     * schreibt nach pcl und nach hidden, aber nicht ins high Latch register
     *
     * @param address die zu schreibende Addresse
     */
    @Override
    public void setCurrentValue(@NotNull final CommandRegisterAddress address) {
        final Bits bits = asLeastSignificantBitFirst(address.asInteger(), Lengths.PROGRAM_ADDRESS_LENGTH);
        pcl.setValue(new RegisterValueImpl(BitUtilities.subBits(bits, 0, 8)));
        hiddenRegisters.setPcHighBits(BitUtilities.subBits(bits, 8, Lengths.PROGRAM_ADDRESS_LENGTH));
        assert address.equals(getCurrentValue());
        log.info("new Program counter is " + getCurrentValue());
    }

    @NotNull
    @Override
    public CommandRegisterAddress getCurrentValue() {
        final Bits lowBits = pcl.getData();
        final Bits highBits = hiddenRegisters.getPcHighBits();
        return new CommandRegisterAddressImpl(BitUtilities.concat(lowBits, highBits));
    }

    @Override
    public void increment() {
        final int pcL = pcl.getData().asInteger();
        if (pcL == 255) {
            log.info("Programm low  counter overflow detected");
        }
        setCurrentValue(CommandRegisterAddressImpl.createUnSafe(getCurrentValue().asInteger() + 1));


    }
}
